/*
 * Copyright 2009 Tran Nhut Trung.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and 
 * limitations under the License.
 */
package com.gdevelop.gwtxp.rebind.gwt;


import com.gdevelop.gwtxp.rebind.Tag;
import com.gdevelop.gwtxp.rebind.el.ELParser;
import com.gdevelop.gwtxp.rebind.el.Node;

import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JParameterizedType;
import com.google.gwt.core.ext.typeinfo.JType;
import com.google.gwt.core.ext.typeinfo.NotFoundException;

import org.eclipse.core.databinding.observable.gwt.internal.widgets.ScrollTable;

import org.w3c.dom.Attr;


public class ScrollTableTag extends FlexTableTag{
  private String var = null;
  
  public ScrollTableTag() {
  }

  public Class getUIClass() {
    return ScrollTable.class;
  }

  public String[] getImports(){
    return new String[]{"org.eclipse.core.databinding.observable.gwt.internal.widgets.*"};
  }

  public void generateInitStart() throws NotFoundException {
    String values = this.getAttribute("values");
    String var = this.getAttribute("var");
    JClassType returnType = null;
    Node elNode = ELParser.parse(values);
    returnType = elNode.getReturnType(elContext);
    if ((values != null) && (var != null) && (TYPE_List.isAssignableFrom(returnType))){
      JType elementType = null;
      if (returnType instanceof JParameterizedType){
        JParameterizedType parameterizedType = (JParameterizedType)returnType;
        if (TYPE_IObservableList.isAssignableFrom(parameterizedType.getRawType())){
          elementType = parameterizedType.getTypeArgs()[0];
        }
      }else if (returnType.getSuperclass() instanceof JParameterizedType){
        JParameterizedType parameterizedType = (JParameterizedType)returnType.getSuperclass();
        if (TYPE_IObservableList.isAssignableFrom(parameterizedType.getRawType())){
          elementType = parameterizedType.getTypeArgs()[0];
        }
      }
      if (elementType == null){
        throw new RuntimeException("DataTable supports list only.");
      }
      if (!(elementType instanceof JClassType)){
        throw new RuntimeException("DataTable supports list of object only.");
      }
      this.elContext.addBean(var, (JClassType)elementType);
      
      this.var = var;
    }
    
    super.generateInitStart();
  }

  public void generateInitEnd() throws NotFoundException{
    if (var != null){
      this.elContext.removeBean(var);
    }
    super.generateInitEnd();
  }

  public void _generateDeclaration() {
    String className = this.getUIClass().getSimpleName();
    out.print(className + " " + varName + " = new " + className+ "();");
  }

  public void generateAddUI(Tag child) {
    // No-op, the TableCellTag handle the adding
  }

  public void generateSetAttributeByExpression(Attr attr) throws NotFoundException {
    if (("values".equals(attr.getLocalName()))
      || ("var".equals(attr.getLocalName()))
    ){
      return;
    }
    super.generateSetAttributeByExpression(attr);
  }
  
  public void generateSetCellAttibutes(TableCellTag cellTag, Tag child){
    String row = cellTag.getAttribute("row");
    String col = cellTag.getAttribute("col");
    //x if ((row == null) || (col == null)){
    if (col == null){
      throw new RuntimeException("TableCell must have row and col attribute.");
    }
    String rowSpan = cellTag.getAttribute("rowSpan");
    String colSpan = cellTag.getAttribute("colSpan");

    if (cellTag instanceof HeaderCellTag){
      if (rowSpan != null){
        // TODO out.println(this.getVarName() + ".getHeaderTable().getFlexCellFormatter().setRowSpan(" + row + ", " + col + ", " + rowSpan + ");");
      }
      if (colSpan != null){
        // TODO out.println(this.getVarName() + ".getHeaderTable().getFlexCellFormatter().setColSpan(" + row + ", " + col + ", " + colSpan + ");");
      }
    }else{  // Body
      if (rowSpan != null){
        out.println(this.getVarName() + ".getFlexCellFormatter().setRowSpan(" + row + ", " + col + ", " + rowSpan + ");");
      }
      if (colSpan != null){
        out.println(this.getVarName() + ".getFlexCellFormatter().setColSpan(" + row + ", " + col + ", " + colSpan + ");");
      }
    }
    
    super.generateSetCellAttibutes(cellTag, child);
  }

  public void generateAddTableCell(TableCellTag cellTag, Tag child) throws NotFoundException {
    String row = cellTag.getAttribute("row");
    String col = cellTag.getAttribute("col");
    //x if ((row == null) || (col == null)){
    if (col == null){
      throw new RuntimeException("TableCell must have col attribute.");
    }

    if (cellTag instanceof HeaderCellTag){
      //TODO: out.println(this.varName + ".setHeaderWidget(" + row + ", " + col + ", " + child.getVarName() + ");");
      out.println(this.varName + ".getHeader().setWidget(" + row + ", " + col + ", " + child.getVarName() + ");");
      
      String columnWidth = cellTag.getAttribute("columnWidth");;
      if (columnWidth != null){
        out.println(this.varName + ".getColumnFormatter().setWidth(" + col + ", \"" + columnWidth + "\");");
      }
    }else{
      child.generateDeclaration();
      out.println(this.varName + ".getBody().setWidget(row, " + col + ", " + child.getVarName() + ");");
    }
  }

  protected void generateTargetObservaleVaue(Attr attr){
    if ("selectedIndex".equals(attr.getName())){
      out.println("new ScrollTableIndexObservableValue(" + varName + ")");
    }else{
      super.generateTargetObservaleVaue(attr);
    }
  }

  protected void generateTargetObservaleList(Attr attr) throws NotFoundException {
    if ("values".equals(attr.getName())){
      Node elNode = ELParser.parse(attr.getValue());
      JClassType returnType = elNode.getReturnType(elContext);
      if (!TYPE_List.isAssignableFrom(returnType)){
        throw new RuntimeException("DataTable supports list only.");
      }
      JType elementType = null;
      if (returnType instanceof  JParameterizedType){
        JParameterizedType parameterizedType = (JParameterizedType)returnType;
        if (TYPE_IObservableList.isAssignableFrom(parameterizedType.getRawType())){
          elementType = parameterizedType.getTypeArgs()[0];
        }
      }else if (returnType.getSuperclass() instanceof JParameterizedType){
        JParameterizedType parameterizedType = (JParameterizedType)returnType.getSuperclass();
        if (TYPE_IObservableList.isAssignableFrom(parameterizedType.getRawType())){
          elementType = parameterizedType.getTypeArgs()[0];
        }
      }
      if (elementType == null){
        throw new RuntimeException("Unable to determine element type of the list.");
      }
      String var = this.getAttribute("var");
      if (var == null){
        throw new RuntimeException("No attribute value for 'var'.");
      }
      
      String dataTypeName = elementType.getQualifiedSourceName();
      
      out.println("new ScrollTableObservableList(" + varName + ", " + dataTypeName + ".class){");
      out.indent();
      out.println("protected void setRow(int row, Object element, Object oldElement){");
      out.indent();
      out.println(dataTypeName + " " + var + "= (" + dataTypeName + ")element;");
      for (Tag ch : children){
        TableCellTag cellTag = (TableCellTag)ch;
        String sectionName = cellTag.getAttribute("sectionName");
        if (sectionName != null){   // not body section
          continue;
        }
        generateSubTag(this, cellTag);
      }
      out.outdent();
      out.println("}");
      
      out.outdent();
      out.println("}");
    }else{
      super.generateTargetObservaleList(attr);
    }
  }

  private void generateSubTag(Tag parent, Tag me) throws NotFoundException {
    if (parent != null){
      parent.generateAddUI(me);
    }

    me.generateInitStart();

    for (Tag child : me.getChildren()){
      generateSubTag(me, child);
    }
    
    me.generateInitEnd();
  }
}
